﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework;
using CoolEngine.Gui;
namespace CoolEngine.Engine.Input
{
    public enum ButtonPressStage
    {
        Down,
        Up,
        Pressed,
        Released
    }
    [AttributeUsage(AttributeTargets.Method)]
    public sealed class DefaultBoundKeyAttribute : Attribute
    {
        public Keys Key { get; set; }
        public ButtonPressStage ButtonPressStage { get; set; }
        public string Control { get; private set; }
        public DefaultBoundKeyAttribute(Keys key, ButtonPressStage buttonPressStage, string control)
        {
            Key = key;
            ButtonPressStage = buttonPressStage;
            Control = control;
        }
        public DefaultBoundKeyAttribute()
        {

        }
    }
    public static class InputHandler
    {
        private static Dictionary<Keys, string> boundOnDownKeys = new Dictionary<Keys, string>();
        private static Dictionary<Keys, string> boundOnUpKeys = new Dictionary<Keys, string>();
        private static Dictionary<Keys, string> boundPressedKeys = new Dictionary<Keys, string>();
        private static KeyboardState oldKeyboardState = new KeyboardState();
        private static MouseState oldMouseState = new MouseState();
        public static Vector2 MousePosition { get; private set; }
        /// <summary>
        /// Runs commands based on what keys are pressed.
        /// </summary>
        /// <param name="player">The player.</param>
        public static void HandleInput(PlayerIndex player)
        {
            HandleKeyboard(player);
            HandleMouse();
        }

        private static void HandleMouse()
        {
            MouseState state = Mouse.GetState();
            MousePosition = new Vector2(state.X, state.Y);
            GuiControl control = (from c in GameManager.GuiRenderer.controls                                  
                                  where c.Value.Visible && c.Value.DrawLocation.Contains(state.X, state.Y)
                                  orderby c.Key descending
                                  select c.Value).FirstOrDefault();
            if (control != null)
            {
                GameManager.Game.IsMouseVisible = control.MouseVisible;
                if (control.CaptureMouse)
                {
                    Mouse.SetPosition(control.DrawLocation.X + control.DrawLocation.Width / 2, control.DrawLocation.Y + control.DrawLocation.Height / 2);
                }
            }

            if (state.LeftButton == ButtonState.Pressed)
            {
                if (oldMouseState.LeftButton == ButtonState.Released)
                {

                    if (control != null)
                    {
                        control.HasFocus = true;
                        control.OnMouseClick(new GuiControl.MouseClickEventArgs(MousePosition, state));
                    }
                }
            }

            oldMouseState = state;
        }

        private static void HandleKeyboard(PlayerIndex player)
        {
            KeyboardState state = Keyboard.GetState(player);
            GuiControl activeControl = GuiControl.ActiveControl;
            if (activeControl != null && activeControl.CaptureKeyboard)
            {
                GuiControl.ActiveControl.OnKeyboardInput(new GuiControl.KeyboardInputEventArgs() { State = state, OldState = oldKeyboardState });
            }
            else
            {
                // Run commands if the keys are down.
                foreach (Keys key in state.GetPressedKeys())
                {
                    if (boundPressedKeys.ContainsKey(key))
                    {
                        HardCodedCommandParser.RunCommand(boundPressedKeys[key]);
                    }
                    if (boundOnDownKeys.ContainsKey(key) && oldKeyboardState.IsKeyUp(key))
                    {
                        HardCodedCommandParser.RunCommand(boundOnDownKeys[key]);
                    }
                    else if (boundOnUpKeys.ContainsKey(key) && oldKeyboardState.IsKeyDown(key))
                    {
                        HardCodedCommandParser.RunCommand(boundOnUpKeys[key]);
                    }
                }
            }
            oldKeyboardState = state;
        }
        /// <summary>
        /// Binds a key to a command.
        /// </summary>
        /// <param name="key">The key.</param>
        /// <param name="command">The command.</param>
        /// <param name="stage">The stage.</param>
        public static void BindKey(Keys key, string command, ButtonPressStage stage)
        {
            switch (stage)
            {
                case ButtonPressStage.Down:
                    boundOnDownKeys.Add(key, command);
                    break;
                case ButtonPressStage.Up:
                    boundOnUpKeys.Add(key, command);
                    break;
                case ButtonPressStage.Pressed:
                    boundPressedKeys.Add(key, command);
                    break;
                default:
                    throw new InvalidOperationException("Wtf?");
            }
        }
    }
}
